<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="btn">发送请求</button>
  <button id="cancel">取消发送</button>
  <script>
    function Axios(config) {
      this.default = config
      this.intercepters = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
      }
    }
    // 用来保存拦截器回调
    function InterceptorManager() {
      this.handlers = []
    }
    // 向数组中压入拦截器回调
    InterceptorManager.prototype.use = function(fulfilled,rejected) {
      this.handlers.push({fulfilled,rejected})
    }

    Axios.prototype.request = function(config) {
      // 发送请求
      // 创建一个promise对象
      let promise = Promise.resolve(config)
      // 声明一个数组
      let chains = [dispatchRequest,undefined]  
      // 处理拦截器
      // 请求拦截器中的回调压入chains中
      this.intercepters.request.handlers.forEach(item=>{
        chains.unshift(item.fulfilled,item.rejected)
      })
      this.intercepters.response.handlers.forEach(item=>{
        chains.push(item.fulfilled,item.rejected)
      })
      while(chains.length) {
        // 让请求拦截器中的返回值控制是否请求，且请求成功的结果决定响应拦截器的返回值
        promise = promise.then(chains.shift(),chains.shift())
      }
      return promise
    }
    Axios.prototype.get = function(config) {
      console.log('发送get请求成功');
    }
    Axios.prototype.post = function(config) {
      console.log('发送post请求成功');
    } 

    // 声明函数 axios调用相当于调用Axios.prototype.request bind调用
    function createInstance(config) {
      let context = new Axios(config)
      let instance = Axios.prototype.request.bind(context)
      Object.keys(Axios.prototype).forEach(key=>{
        instance[key] = Axios.prototype[key]
      })
      Object.keys(context).forEach(key=>{
        instance[key] = context[key]
      })
      return instance
    }
    
    // dispatchRequest函数
    function dispatchRequest(config) {
      // 调用适配器发起请求
      return xhrAdapter(config).then(res=>{
        console.log(res);
        // 响应的结果进行转换
          return res
      },err=>{
        throw err
      })
    }
    // xhr适配器
    function xhrAdapter(config) {
      return new Promise((resolve,reject)=>{
        // 发送Ajax请求
        let xhr = new XMLHttpRequest()
        // 初始化
        xhr.open(config.method,config.url)
        // 发送
        xhr.send()
        // 绑定事件
        xhr.onreadystatechange = function() {
          if(xhr.readyState === 4) {
            // 成功的条件
            if(xhr.status >=200&&xhr.status<300) {
              resolve({
                config,
                data:xhr.response,
                headers:xhr.getAllResponseHeaders(),
                request:xhr,
                status:xhr.status,
                statusText:xhr.statusText
              })
            }
          }
        }
        if(config.cancelToken) {
          config.cancelToken.promise.then(res=>{
            xhr.abort()
          })
        }
      })
    }
    // 取消发送请求
    function cancelToken(executor) {
      // 声明一个变量
      let resolvePromise
      this.promise = new Promise(resolve=>{
        resolvePromise = resolve
      })
      executor(function() {
        resolvePromise()
      })
    }

    let axios = createInstance()
    // axios.request({method:'get',url:'http://localhost:3000/posts'})
    axios.intercepters.request.use(function one(config) {
      console.log('请求拦截器1');
      return config
    },function one(config) {})
    axios.intercepters.request.use(function two(config) {
      console.log('请求拦截器2');
      return config
    },function two(config) {})
    axios.intercepters.response.use(function one(config) {
      
    },function one(config) {})
    axios.intercepters.response.use(function two(config) {
      return config
    },function two(config) {})
    
    let btn = document.getElementById('btn')
    let btn1 = document.getElementById('cancel')
    let cancel = null
    btn.onclick = function() {
      if(cancel !== null) {
        // 取消上一次请求
        cancel()
      }
      let cancelToken1 = new cancelToken(function(c) {
        cancel = c
      })
      axios({method:'get',url:'http://localhost:3000/posts',cancelToken:cancelToken1}).then(res=>{
        console.log(res);
        cancel = null
      })
    }
    btn1.onclick = function() {
      cancel()
    }
  </script>
</body>
</html>